package com.uinnova.product.eam.service.impl;

import com.uinnova.product.eam.config.Env;
import com.uinnova.product.eam.model.BizNodeDto;
import com.uinnova.product.eam.service.IBizArchitectureSvc;
import com.uinnova.product.eam.service.IEamCiSvc;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uino.bean.cmdb.base.LibType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 业务架构的相关服务
 *
 * @author yuhao.guan
 * @version 2020-8-19
 */
@Service
public class BizArchitectureSvcImpl implements IBizArchitectureSvc {

    //private static Logger logger = LoggerFactory.getLogger(BizArchitectureSvcImpl.class);

    @Autowired
    private IEamCiSvc eamCiSvc;

    private static String ATTR_ABILITY = "所属能力";

    private static String ATTR_NAME = "名称";

    private static String ATTR_LEVEL = "层级";

    @Override
    public List<BizNodeDto> getBusinessTree(LibType libType) {
        List<CcCiInfo> bizCiList = eamCiSvc.getCiInfoListByClassName(Env.APP.getBizClassName(), libType);
        Map<String, Set<CcCiInfo>> abilityMap = getBizAbilityMap(bizCiList);

        // 第一层节点
        List<BizNodeDto> rootNodeList = new LinkedList<>();
        for(CcCiInfo bizCi: bizCiList){
            BizNodeDto itemNode = new BizNodeDto();
            itemNode.setName(bizCi.getAttrs().get(ATTR_NAME));
            itemNode.setCiInfo(bizCi);
            String ciLevel = bizCi.getAttrs().get(ATTR_LEVEL);
            if(ciLevel.equalsIgnoreCase("L1")){
                rootNodeList.add(itemNode);
            }
        }
        if (rootNodeList.size() > 0) {
            // 按名称排序
            rootNodeList.sort(Comparator.comparing(BizNodeDto::getName));
        }
        // 构建业务能力树
        rootNodeList.forEach((rootNode)->{
            findChild(rootNode, abilityMap);
        });
        return rootNodeList;
    }

    /**
     * 获取业务能力Map
     * @param bizCiList 全部的业务能力
     *
     * @return Map<业务能力名称, 属于此业务能力的子业务能力CI集合>
     */
    private Map<String, Set<CcCiInfo>> getBizAbilityMap(List<CcCiInfo> bizCiList){
        Map<String, Set<CcCiInfo>> abilityMap = new HashMap<>();
        for(CcCiInfo itemCi: bizCiList){
            if(itemCi.getAttrs().containsKey(ATTR_ABILITY)) {
                String parentAbility = itemCi.getAttrs().get(ATTR_ABILITY);
                if (!abilityMap.containsKey(parentAbility)) {
                    abilityMap.put(parentAbility, new HashSet<>());
                }
                abilityMap.get(parentAbility).add(itemCi);
            }
        }
        return abilityMap;
    }

    /**
     * 获取指定业务系统的子业务系统
     *
     * @param bizNode 业务系统节点
     * @param abilityMap 所有业务系统列表
     */
    private void findChild(BizNodeDto bizNode, Map<String, Set<CcCiInfo>> abilityMap) {
        String parentNodeName = bizNode.getName();
        String parentNodeLevel = bizNode.getCiInfo().getAttrs().get(ATTR_LEVEL);
        // 如果业务能力包含子业务能力
        if (abilityMap.containsKey(parentNodeName)) {
            List<BizNodeDto> childList = new ArrayList<>();
            for (CcCiInfo itemCi : abilityMap.get(parentNodeName)) {
                if (itemCi.getAttrs().containsKey(ATTR_ABILITY)) {
                    String parentAbility = itemCi.getAttrs().get(ATTR_ABILITY);
                    String level = itemCi.getAttrs().get(ATTR_LEVEL);
                    // 如果系统的所属能力为给定CI的名称并且两个系统不在同一层级, 则认为此系统为给定CI的子业务系统
                    if (parentAbility.equalsIgnoreCase(parentNodeName) && !level.equalsIgnoreCase(parentNodeLevel)) {
                        BizNodeDto childNode = new BizNodeDto();
                        childNode.setCiInfo(itemCi);
                        childNode.setName(itemCi.getAttrs().get(ATTR_NAME));
                        childList.add(childNode);
                    }
                }
            }
            if (childList.size() > 0) {
                // 按名称排序
                childList.sort(Comparator.comparing(BizNodeDto::getName));
            }
            bizNode.setChildren(childList);
            // 递归查询
            bizNode.getChildren().forEach((nextNode) -> {
                findChild(nextNode, abilityMap);
            });
        }
    }

}
